import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;

import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;


public class WebSocketServerHandler extends SimpleChannelInboundHandler {

    private static final Logger logger = Logger.getLogger(WebSocketServerHandler.class.getName());
    private WebSocketServerHandshaker handshaker;

    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        //webSocket第一次握手请求消息由HTTP协议承载
        //传统的HTTP接入
        if(msg instanceof FullHttpRequest){
            //处理websocket握手请求
            handleHttpRequest(ctx,(FullHttpRequest)msg);
        }else if (msg instanceof WebSocketFrame){
            handleWebSocketFrame(ctx,(WebSocketFrame)msg);
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }
    private void handleHttpRequest(ChannelHandlerContext ctx,FullHttpRequest req){
        //请求不是websocket握手请求或HTTP解码失败,返回HTTP 400异常
        if (!req.getDecoderResult().isSuccess()
            || (!"websocket".equals(req.headers().get("Upgrade")))){
            this.sendHttpResponse(ctx,req,new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
        }
        //构造握手响应返回,
        WebSocketServerHandshakerFactory wsFactor = new
                WebSocketServerHandshakerFactory("ws://localhost:8080/websocket",null,false);
        handshaker = wsFactor.newHandshaker(req);
        if (handshaker == null){
            WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel());
        }else {
            //加载webSocket相关的编解码器
            handshaker.handshake(ctx.channel(),req);
        }
    }

   public void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame){
        //判断是否关闭链路指令
       if (frame instanceof CloseWebSocketFrame){
           handshaker.close(ctx.channel(),((CloseWebSocketFrame) frame).retain());
            return;
       }
       //判断是否ping消息
       if (frame instanceof PingWebSocketFrame){
           ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
           return;
       }
       //文本消息
       if (!(frame instanceof TextWebSocketFrame)){
           return;
       }
       //返回应答消息
       String request = ((TextWebSocketFrame) frame).text();
       if (logger.isLoggable(Level.FINE)){
           logger.fine(String.format("%s  received  %s",ctx.channel(),request));
       }
       ctx.channel().writeAndFlush(new TextWebSocketFrame(request+",欢迎使用Netty webSocket服务,当期时刻" +
               new Date().toString()));
   }
   private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest  req, FullHttpResponse res){
        //返回客户端应答
       if (res.getStatus().code() != 200){
            ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8);
            res.content().writeBytes(buf);
            buf.release();
            HttpUtil.setContentLength(res,res.content().readableBytes());
       }
       //如果是非keep-alive,关闭链接
       ChannelFuture future = ctx.channel().writeAndFlush(res);
       if (!HttpUtil.isKeepAlive(req) || res.getStatus().code() != 200){
           future.addListener(ChannelFutureListener.CLOSE);
       }
   }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
